<?php

namespace app\common\service;

use app\common\cachemodel\MapUnlockResult;
use app\common\cachemodel\MonthFortune;
use app\common\cachemodel\NatalReport;
use app\common\cachemodel\Recode;
use app\common\cachemodel\YearFortune;
use app\common\cachemodel\zl1_relation\Zl1AstrCommunityArticle;
use app\common\cachemodel\zl1_relation\Zl1RelationAnalysisFitYou;
use app\common\cachemodel\zl1_relation\Zl1RelationAnalysisIdea;
use app\common\cachemodel\zl1_relation\Zl1RelationAnalysisReport;
use app\common\cachemodel\zl2\Zl2FamousPersonRecode;
use app\common\cachemodel\zl2\Zl2MentalTestExercise;
use app\common\cachemodel\zl2\Zl2Surprise;
use app\common\cachemodel\zl2\Zl2SurpriseCouponDiscount;
use app\common\cachemodel\zl2\Zl2UserSurpriseRecord;
use app\common\cachemodel\ZlSynastryReport;
use app\common\lib\astrolog\DailyFortune;
use app\common\model\Map as MapRecode;
use think\Db;

/**
 * 星运变动惊喜
 */
class AstroFortuneSurprise
{
    /**
     * 用户信息
     * @var null
     */
    protected $userInfo = null;

    /**
     * 自己的档案信息
     */
    protected $selfRecode = null;

    /**
     * 单例
     * @var AstroFortuneSurprise
     */
    protected static $instance;

    /**
     * 优惠券信息
     * @var null |array
     */
    protected $couponInfo = null;

    /**
     * 惊喜数据 1=>星座讨论 2=>占星知识 3=>心理测试 4=>名人星盘 5=>卡券
     * @var array
     */
    protected $surpriseData = [
        1 => null,  // 星座讨论
        2 => null,  // 占星知识
        3 => null,  // 心理测试
        4 => null,  // 名人星盘
        5 => null,  // 卡券
    ];

    protected $lastSurpriseId = [
        1 => 0,
        2 => 0,
        3 => 0,
        4 => 0,
        5 => 0,
    ];

    /**
     * 构造方法
     * 单例模式，私有化
     * 只能通过 getInstance 公共方法获取实例
     * AstroFortuneSurprise constructor.
     */
    private function __construct()
    {
    }

    /**
     * 获取实例
     * @return AstroFortuneSurprise
     */
    public static function getInstance(): AstroFortuneSurprise
    {
        if (!(self::$instance instanceof self))
        {
            self::$instance = new self();
        }
        return self::$instance;
    }

    /**
     * 设置用户信息
     * @param array $userInfo
     * @return $this
     */
    public function setUserInfo(array $userInfo): AstroFortuneSurprise
    {
        $this->userInfo = $userInfo;
        $uid = $userInfo['id'];
        $data = (new Zl2UserSurpriseRecord())->whereIn('id', function ($query) use ($uid)
        {
            $query->table('wechat_backup_07_18_14_43_00.zl2_user_surprise_record')->where('uid', $uid)->group('type')->field('max(id)');
        })->column('sid', 'type');

        $this->lastSurpriseId = [
            1 => (int)($data[1] ?? 0),
            2 => (int)($data[2] ?? 0),
            3 => (int)($data[3] ?? 0),
            4 => (int)($data[4] ?? 0),
            5 => (int)($data[5] ?? 0),
        ];

        return $this;
    }

    /**
     * 设置用户信息
     * @param array $recode
     * @return $this
     */
    public function setSelfRecode(array $recode): AstroFortuneSurprise
    {
        $this->selfRecode = $recode;
        return $this;
    }

    /**
     * 获取自己的档案信息
     * @return array
     * @throws \Exception
     */
    public function getSelfRecodeInfo(): array
    {
        if (!$this->selfRecode)
        {
            $this->selfRecode = (new Recode())->getInfoById($this->userInfo['rid']);
        }

        return $this->selfRecode;
    }

    /**
     * 获取
     * 惊喜类型 0=>不排除 1=>星座讨论 2=>占星知识 3=>心理测试 4=>名人星盘 5=>卡券
     * @param int $excludeType 首次 排除类型
     * @param int $num 获取几个惊喜
     * @return array
     */
    public function getSurprise(int $excludeType, int $num)
    {
        $resData = [];
        for ($i = 0; $i < $num; $i++)
        {
            $surpriseTypes = [1 => 1, 2 => 2, 3 => 3, 4 => 4, 5 => 5];
            do
            {
                unset($surpriseTypes[$excludeType]);
                $surType = array_rand($surpriseTypes);
                switch ($surType)
                {
                    case 1: // 获取星座讨论
                        $data = $this->getAstrCommunityAtricleId();
                        break;
                    case 2: // 获取占星知识
                        $data = $this->getAstrAtricleId();
                        break;
                    case 3: // 获取心理测试
                        $data = $this->getMentalTestId();
                        break;
                    case 4: // 获取名人星盘
                        $data = $this->getFamousPersonId();
                        break;
                    default: // 获取优惠券
                        $data = $this->getCouponId();
                }
                if (!$data['status'])
                {   // 如果 为命中改类型 则排除改类型
                    $excludeType = $surType;
                }
            } while (!$data['status']);
            // 下次获取排除当前
            $excludeType = $surType;
            $resData[] = [
                'type' => $surType,
                'id' => $data['id'],
                'sid_node_id' => $data['sid_node_id'] ?? 0,
            ];
        }

        return $resData;
    }

    /**
     * 获取星座讨论文章ID
     * @return array
     */
    protected function getAstrCommunityAtricleId()
    {
        $surpriseType = 1; // 1=>星座讨论 2=>占星知识 3=>心理测试 4=>名人星盘 5=>卡券
        $ids = $this->getSurpriseData($surpriseType);
        // 排除上一次出现的ID
        foreach ($ids as $signId => $idItem)
        {
            $idItem = (int)$idItem;
            if ($idItem === $this->lastSurpriseId[$surpriseType])
            {
                unset($ids[$signId]);
                continue;
            }
            $ids[$signId] = $idItem;
        }

        if ($ids)
        {
            $resId = array_rand($ids, 1);
            // 更新最后一次当前类型惊喜ID
            $this->lastSurpriseId[$surpriseType] = $ids[$resId];

            return [
                'status' => true,  // 惊喜获取状态
                'id' => $ids[$resId], // 惊喜ID
            ];
        } else
        {
            return [
                'status' => false,  // 惊喜获取状态
                'id' => 0, // 惊喜ID
            ];
        }
    }

    /**
     * 获取占星知识ID
     * @return array
     */
    protected function getAstrAtricleId()
    {
        $surpriseType = 2; // 1=>星座讨论 2=>占星知识 3=>心理测试 4=>名人星盘 5=>卡券
        $ids = $this->getSurpriseData($surpriseType);
        // 排除上一次出现的ID
        unset($ids[$this->lastSurpriseId[$surpriseType]]);

        if ($ids)
        {
            $resId = array_rand($ids, 1);
            // 更新最后一次当前类型惊喜ID
            $this->lastSurpriseId[$surpriseType] = $resId;

            return [
                'status' => true,  // 惊喜获取状态
                'id' => $resId, // 惊喜ID
            ];
        } else
        {
            return [
                'status' => false,  // 惊喜获取状态
                'id' => 0, // 惊喜ID
            ];
        }
    }

    /**
     * 获取名人星盘ID
     * @return array
     */
    protected function getFamousPersonId()
    {
        $surpriseType = 4; // 1=>星座讨论 2=>占星知识 3=>心理测试 4=>名人星盘 5=>卡券
        // todo  逻辑待调整
        $ids = $this->getSurpriseData($surpriseType);
        // 排除上一次出现的ID
        unset($ids[$this->lastSurpriseId[$surpriseType]]);

        if ($ids)
        {
            $resId = array_rand($ids, 1);
            // 更新最后一次当前类型惊喜ID
            $this->lastSurpriseId[$surpriseType] = $resId;

            return [
                'status' => true,  // 惊喜获取状态
                'id' => $resId, // 惊喜ID
            ];
        } else
        {
            return [
                'status' => false,  // 惊喜获取状态
                'id' => 0, // 惊喜ID
            ];
        }
    }

    /**
     * 获取心理测试ID
     * @return array
     */
    protected function getMentalTestId()
    {
        $surpriseType = 3; // 1=>星座讨论 2=>占星知识 3=>心理测试 4=>名人星盘 5=>卡券

        $ids = $this->getSurpriseData($surpriseType);
        // 排除上一次出现的ID
        unset($ids[$this->lastSurpriseId[$surpriseType]]);

        if ($ids)
        {
            $resId = array_rand($ids, 1);
            // 更新最后一次当前类型惊喜ID
            $this->lastSurpriseId[$surpriseType] = $resId;

            return [
                'status' => true,  // 惊喜获取状态
                'id' => $resId, // 惊喜ID
            ];
        } else
        {
            return [
                'status' => false,  // 惊喜获取状态
                'id' => 0, // 惊喜ID
            ];
        }
    }

    /**
     * 获取卡券ID
     * @return array
     * @throws \Exception
     */
    protected function getCouponId()
    {
        $surpriseType = 5; // 1=>星座讨论 2=>占星知识 3=>心理测试 4=>名人星盘 5=>卡券
        $gidConfig = [
            2 => [ //日运 2=>'当天日运' 3=>'月度日运' 4=>'季度日运' 5=>'半年日运' 5=>'年度日运'
                2 => 2, 3 => 3, 4 => 4, 5 => 5
            ],
            3 => [ //月运 20=>'一个月运势' 21=>'三个月运势' 22=>'六个月运势' 23=>'十二月运势'
                20 => 20, 21 => 21, 22 => 22, 23 => 23
            ],
            4 => [ //年运 24=>'一年运势' 25=>'三年运势' 26=>'五年运势' 27=>'十年运势'
                24 => 24, 25 => 25, 26 => 26, 27 => 27
            ],
            5 => [ //幸运之城 7=>'成就线' 8=>'安居线' 9=>'智慧线' 10=>'桃花线' 11=>'激情线' 12=>'幸运线' 13=>'成长线' 14=>'变革线' 15=>'梦想线' 16=>'生死线' 17=>'宿命线' 18=>'命运之城' 19=>'幸运之城'
                7 => 7, 8 => 8, 9 => 9, 10 => 10, 11 => 11, 12 => 12, 13 => 13, 14 => 14, 15 => 15, 16 => 16, 17 => 17, 18 => 18, 19 => 19,
            ],
            7 => [ //一生报告 39=>'恋爱格局预测报告' 40=>'婚姻格局预测报告' 41=>'财富格局预测报告' 42=>'事业格局预测报告' 52=>'学业格局预测报告'
                39 => 39, 40 => 40, 41 => 41, 42 => 42, 52 => 52
            ],
            17 => [ //合盘报告 62=>'暗恋一年' 63=>'暗恋三年' 64=>'分手一年' 65=>'分手三年' 66=>'热恋一年' 67=>'热恋三年' 68=>'热恋五年' 69=>'热恋十年' 70=>'婚姻一年' 71=>'婚姻三年' 72=>'婚姻五年' 73=>'婚姻十年'
                62 => 62, 63 => 63, 64 => 64, 65 => 65, 66 => 66, 67 => 67, 68 => 68, 69 => 69, 70 => 70, 71 => 71, 72 => 72, 73 => 73,
            ],
            23 => [ //适合你的Ta 84=>'终极契合型' 85=>'甜蜜幸福型' 86=>'虐恋型' 87=>'打包解锁'
                84 => 84, 85 => 85, 86 => 86, 87 => 87,
            ],
            24 => [ //你的理想型
                88 => 88, //你的理想型
            ],
            25 => [ //怎么追求TA
                89 => 89, //怎么追求TA
            ],
        ];
        if ($this->couponInfo)
        {
            $gids = $this->couponInfo['gids'];
            $goodTypes = $this->couponInfo['goodTypes'];
            $gids2 = $this->couponInfo['gids2'];
            $goodTypes2 = $this->couponInfo['goodTypes2'];
        } else
        {
            $gids = $gidConfig[2];
            $goodTypes[2] = 2;
            $recodeInfo = $this->getSelfRecodeInfo();
            // 判断月运是否购买     ------------
            // 获取已解锁的时间范围
            $unlockMonths = (new MonthFortune())->getReocdeFortuneUnlockMonths($this->userInfo['rid']);
            $time_range = array_map(function ($timeValue)
            {
                return date('Y-n', strtotime($timeValue));
            }, $unlockMonths);
            [$year, $month, $day] = explode('-', date('Y-m-d'));
            if (in_array(date('Y-n', strtotime('+1 month')), $time_range, true))
            {   // 下月已解锁
                if ($day <= 10 && !in_array(date('Y-n'), $time_range, true))
                { // 小于10号的时候  没有解锁当月
                    $gids += $gidConfig[3];
                    $goodTypes[3] = 3;
                }
            } else
            {   // 未解锁
                $gids += $gidConfig[3];
                $goodTypes[3] = 3;
            }
            // 判断年运是否购买     ------------
            $unlockYears = (new YearFortune())->getReocdeFortuneUnlockYears($this->userInfo['rid']);
            $unlockYears = array_map(function ($timeValue)
            {
                return (string)($timeValue);
            }, $unlockYears);
            $year1 = (string)($year + 1);
            if (in_array($year1, $unlockYears, true))
            {   // 下月已解锁
                if ($month <= 5 && !in_array($year, $time_range, true))
                { // 小于10号的时候  没有解锁当月
                    $gids += $gidConfig[4];
                    $goodTypes[4] = 4;
                }
            } else
            {   // 未解锁
                $gids += $gidConfig[4];
                $goodTypes[4] = 4;
            }
            // 幸运之城     ------------
            //获取用户当前已解锁的数据
            $unlockMapIds = (new MapUnlockResult())->getUnlockIdsFromCache(3, $this->userInfo['rid']);
            if (!$unlockMapIds)
            {
                $gids += $gidConfig[5];
                $goodTypes[5] = 5;
            }
            // 恋爱合盘报告   ------------
            $synastryReportIds = (new ZlSynastryReport())->getSynastryReportIds($this->userInfo['id'], $this->userInfo['rid'], 0, 1);
            if (!$synastryReportIds)
            {
                $gids += $gidConfig[17];
                $goodTypes[17] = 17;
            }
            // 一生报告     ------------
            $NatalReportModel = new NatalReport();
            $unlockReport = $NatalReportModel->getNatalReport2($recodeInfo);
            $NatalReportGids = $gidConfig[7];
            foreach ($unlockReport as $gid => $reportInfo)
            {
                unset($NatalReportGids[$gid]);
            }
            $gids += $NatalReportGids;
            if ($NatalReportGids)
            {
                $goodTypes[7] = 7;
            }
            // 关系研究所    ------------
            //获取 怎么追求她
            $getFollowPageData = (new Zl1RelationAnalysisReport())->getListPage($this->userInfo['id'], 'id', ['id'], 1, 'desc', 0);
            if ($getFollowPageData['total'] === 0)
            {
                $gids += $gidConfig[25];
                $goodTypes[25] = 25;
            }
            //获取 适合你的她
            $getFitYouReportData = (new Zl1RelationAnalysisFitYou())->getFitYouReportALL($this->userInfo['id'], $this->userInfo['rid'], []);
            if (!$getFitYouReportData)
            {
                $gids += $gidConfig[23];
                $goodTypes[23] = 23;
            }
            // 获取我的理想型解锁
            $unLockCaseData = (new Zl1RelationAnalysisIdea())->getUnlockCaseList($this->userInfo['id']);
            if (!$unLockCaseData)
            {
                $gids += $gidConfig[24];
                $goodTypes[24] = 24;
            }
            // 排除不购买项
            $age = $year - $recodeInfo['year'];
            if (isset($gids[52]) && $age >= 30)
            {   // 30岁以上 排除 学业报告
                unset($gids[52]);
            }
            // 选出弱购买项
            $gids2 = [];    // 弱购买项
            $goodTypes2 = [];   //  弱购买项
            // todo 获得8折以上优惠券未使用
            if (isset($gids[52]) && $age >= 25 && $age < 30)
            { // 学业报告
                $gids2[52] = 52;
                unset($gids[52]);
                $goodTypes2[7] = 7;
            }
            if (isset($gids[39]) && $age >= 40)
            { // 恋爱报告
                $gids2[39] = 39;
                unset($gids[39]);
                $goodTypes2[7] = 7;
            }
            if (!isset($gids[39]) && !isset($gids[40]) && !isset($gids[41]) && !isset($gids[42]) && !isset($gids[52]))
            {
                unset($goodTypes[7]);
            }
            $this->couponInfo = [
                'gids' => $gids,
                'goodTypes' => $goodTypes,
                'gids2' => $gids2,
                'goodTypes2' => $goodTypes2,
            ];
        }
        $resGids = [];
        $resGidTypes = [];
        // 判断 购买项
        if ($gids && $gids2)
        {   // 既有强购买项 又有弱购买项
            $n = mt_rand(1, 10);
            if ($n === 1)
            {   // 取弱项
                $resGids = $gids2;
                $resGidTypes = $goodTypes2;
            } else
            {   // 取强项
                $resGids = $gids;
                $resGidTypes = $goodTypes;
            }
        } elseif ($gids && !$gids2)
        { // 有强购买项 没有 弱购买项
            $resGids = $gids;
            $resGidTypes = $goodTypes;
        } elseif (!$gids && $gids2)
        { // 没有强购买项 有弱购买项
            $n = mt_rand(1, 10);
            if ($n <= 3)
            {
                $resGids = $gids2;
                $resGidTypes = $goodTypes2;
            } else
            {
                // 日月年随机取1
                $resGids += $gidConfig[2];
                $resGids += $gidConfig[3];
                $resGids += $gidConfig[4];
                $resGidTypes = [2 => 2, 3 => 3, 4 => 4];
            }
        } elseif (!$gids && !$gids2)
        { // 没有强购买项 也没有弱购买项
            $n = mt_rand(1, 2);
            if ($n === 1)
            {   // 日月年随机取1
                $resGids += $gidConfig[2];
                $resGids += $gidConfig[3];
                $resGids += $gidConfig[4];
                $resGidTypes = [2 => 2, 3 => 3, 4 => 4];
            } else
            {   // 重摇
                return [
                    'status' => false,  // 惊喜获取状态
                    'id' => 0, // 惊喜ID
                ];
            }
        }
        // 获取 神秘惊喜 卡券信息
        $surpriseCoupon = $this->getSurpriseData($surpriseType);
        if (!$surpriseCoupon)
        {   // 重摇
            return [
                'status' => false,  // 惊喜获取状态
                'id' => 0, // 惊喜ID
            ];
        }
        // 获取符合的优惠券
        $resCouponTypeInfos = [];
        foreach ($surpriseCoupon as $surpriseCouponItem)
        {
            $surpriseCouponItem['extend']['use_range'] = (int)$surpriseCouponItem['extend']['use_range'];
            if (isset($resGidTypes[$surpriseCouponItem['extend']['use_range']]))
            {
                if ($surpriseCouponItem['extend']['use_range'] === 7)
                {
                    $cgids = explode(',', $surpriseCouponItem['extend']['gids']);
                    if (array_intersect($resGids, $cgids))
                    {
                        $resCouponTypeInfos[$surpriseCouponItem['id']] = $surpriseCouponItem;
                    }
                }
            }
        }

        if ($resCouponTypeInfos)
        {   // 有命中要求的优惠券
            $i = array_rand($resCouponTypeInfos, 1);
            $resSurprise = $resCouponTypeInfos[$i];
        } else
        {   // 则在所有的优惠券中随机取一个
            $i = array_rand($surpriseCoupon, 1);
            $resSurprise = $surpriseCoupon[$i];
        }

        $surpriseCouponDiscountModel = new Zl2SurpriseCouponDiscount();
        $surpriseCouponDiscountList = $surpriseCouponDiscountModel->getCouponDiscountData($resSurprise['id']);
        $randNum = mt_rand(1, $surpriseCouponDiscountList['max']);

        $sNum = 0;
        $sidNodeId = null;
        foreach ($surpriseCouponDiscountList['list'] as $itemData)
        {
            if ($randNum > $sNum && $randNum <= $sNum + $itemData['probability'])
            {
                $sidNodeId = $itemData['id'];
                break;
            }

            $sNum += $itemData['probability'];
        }

        return [
            'status' => true,  // 惊喜获取状态
            'id' => $resSurprise['id'], // 惊喜ID
            'sid_node_id' => $sidNodeId
        ];
    }

    /**
     * 获取惊喜数据
     * @param int $type 1=>星座讨论 2=>占星知识 3=>心理测试 4=>名人星盘 5=>卡券
     * @return void
     */
    public function getSurpriseData(int $type)
    {
        if ($this->surpriseData[$type])
        {
            return $this->surpriseData[$type];
        }
        switch ($type)
        {
            case 1:
                $articleDatas = (new Zl1AstrCommunityArticle())->getHotArticleByToday(time());
                $recodeInfo = $this->getSelfRecodeInfo();
                $ids = [];
                $sun = explode('-', $recodeInfo['sun'])[0];
                if (isset($articleDatas[$sun]))
                {   // 太阳
                    $ids[$sun] = $articleDatas[$sun];
                }
                $moon = explode('-', $recodeInfo['moon'])[0];
                if (isset($articleDatas[$moon]))
                {   // 月亮
                    $ids[$moon] = $articleDatas[$moon];
                }
                $asc = explode('-', $recodeInfo['asc'])[0];
                if (isset($articleDatas[$asc]))
                {   // 上升
                    $ids[$asc] = $articleDatas[$asc];
                }
                $this->surpriseData[$type] = $ids;
                break;
            case 2:
                $num = Db::table('app_recode')->where(['uid' => $this->userInfo['id'], 'status' => 1])->count();
                // 档案数 大于15高级  小于等于15低级
                $secondType = $num > 15 ? 2 : 1;
                $surpriseModel = new Zl2Surprise();
                $this->surpriseData[$type] = $surpriseModel->getAllIds(2, $secondType);
                break;
            case 3:
                $mentalTestExerciseModel = new Zl2MentalTestExercise();
                $this->surpriseData[$type] = $mentalTestExerciseModel->getAllIds();
                break;
            case 4:
                $famousPersonRecodeModel = new Zl2FamousPersonRecode();
                $this->surpriseData[$type] = $famousPersonRecodeModel->getAllIds();
                break;
            case 5:
                $this->surpriseData[$type] = (new Zl2Surprise())->getAllData(1);
                break;
            default:
        }

        return $this->surpriseData[$type];
    }
}